package cn.mothin.frame.help;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import cn.mothin.frame.bean.MenuPacket;
import cn.mothin.frame.core.annotation.Dictionary;
import cn.mothin.frame.core.annotation.Module;
import cn.mothin.frame.core.annotation.NeedPermission;
import cn.mothin.frame.core.annotation.NeedPermissionTemplate;
import cn.mothin.frame.core.annotation.OperationLink;
import cn.mothin.frame.core.annotation.OperationLinks;
import cn.mothin.frame.core.annotation.SystemConfigType;
import cn.mothin.frame.core.base.BaseConfig;
import cn.mothin.frame.core.exception.SystemException;
import cn.mothin.frame.core.interfaces.IDictionary;
import cn.mothin.frame.core.interfaces.ISqlHelper;
import cn.mothin.frame.core.interfaces.system.IConfig;
import cn.mothin.frame.util.ClassUtil;
import cn.mothin.frame.util.JsonUtil;
import cn.mothin.frame.util.SpringUtil;
import cn.mothin.frame.util.StringUtil;

@Component("51d2f8afbe310e3bec0b5c21")
public class ApplicationBaseInit {
	protected final Log log = LogFactory.getLog(getClass());
	@Autowired
	private ActionScanner actionScanner;
	@Autowired
	private ISqlHelper sqlHelper;
	@Autowired
	private JsonUtil jsonUtil;

	/**
	 * 初始化系统字典项 OK
	 */
	@SuppressWarnings("unchecked")
	public void initDictionary() {
		List<Class<?>> list = new ArrayList<Class<?>>();

		Map<String, IDictionary> map = SpringUtil.getApplicationContext()
				.getBeansOfType(IDictionary.class);

		String sql = null;
		for (String key : map.keySet()) {
			IDictionary iDictionary = map.get(key);
			Class<?> c = iDictionary.getClass();
			if (list.contains(c)) {
				continue;
			}
			if (ClassUtil.hasInterface(c, IDictionary.class)
					&& ClassUtil.hasAnnotation(c, Dictionary.class)) {
				Dictionary dictionary = c.getAnnotation(Dictionary.class);

				sql = "SELECT COUNT(0) FROM dictionary_type WHERE id=?";
				if (sqlHelper.queryCount(sql, dictionary.id()) == 0) {
					sql = "INSERT INTO dictionary_type(id,name,innate,allowConfig,treeStructure,ordinal,memo,deleted) values(?,?,TRUE,?,?,?,?,FALSE)";
					sqlHelper.execute(sql, dictionary.id(),
							dictionary.caption(),
							dictionary.allowConfig(),
							dictionary.treeStructure(), 
							0,
							dictionary.memo());
				}
				List<IDictionary> dictionaryList = null;
				try {
					dictionaryList = (List<IDictionary>) c.getMethod(
							"getDictionaryList", Class.class).invoke(null, c);
				} catch (Exception e) {
					throw new SystemException();
				}
				for (IDictionary dic : dictionaryList) {
					sql = "SELECT COUNT(0) FROM dictionary_item WHERE id=?";
					if (sqlHelper.queryCount(sql, dic.getId()) == 0) {
						sql = "INSERT INTO dictionary_item(id,name,nameDisplay,parentId,dictionaryTypeId,innate,ordinal,memo,deleted) values(?,?,?,?,?,TRUE,?,?,FALSE)";
						sqlHelper.execute(sql, dic.getId(), dic.getCaption(),dic.getNameDisplay(),
								dic.getParentId(), dictionary.id(), 
								dic.getOrdinal(), dic.getMemo());
					}
				}
			}
		}
	}

	private String findBelong(Module module) {
		if (module.belong() == Module.NULL_TARGET.class) {
			return null;
		}

		Class<?> c = module.belong();
		if (!ClassUtil.hasAnnotation(c, Module.class)) {
			return null;
		}
		return c.getAnnotation(Module.class).id();
	}

	private String findParent(String parentMethodName, Class<?> c) {
		if (StringUtil.isNullOrEmpty(parentMethodName)) {
			return null;
		}

		Method method = null;
		try {
			method = c.getDeclaredMethod(parentMethodName);
		} catch (Exception e) {
			log.error(e);
			throw new SystemException();
		}

		if (method.isAnnotationPresent(NeedPermission.class)) {
			NeedPermission needPermission = method
					.getAnnotation(NeedPermission.class);
			return needPermission.id();
		} else if (method.isAnnotationPresent(NeedPermissionTemplate.class)) {
			NeedPermissionTemplate needPermissionTemplate = method
					.getAnnotation(NeedPermissionTemplate.class);
			return needPermissionTemplate.id();
		}
		return null;
	}

	private void checkSaveFunctionItem(String id,
			String functionModuleId, String name, String action, String memo,
			String ico, String parentId) {
		String sql = "SELECT COUNT(0) FROM function_item WHERE id = ?";
		if (sqlHelper.queryCount(sql, id) == 0) {
			sql = "INSERT INTO function_item(id, functionModuleId, name, action, memo, ico,parentId) values(?,?,?,?,?,?,?)";
			sqlHelper.execute(sql, id, functionModuleId, name, action, memo,
					ico, parentId);
		}
	}
	
	private void clearOperationLink(){
		String sql="DELETE FROM operation_link";
		sqlHelper.execute(sql);
	}
	
	private void checkSaveOperationLink(String action,String functionItemId,boolean rowOperation,int ordinal,int subOrdinal){
		String sql = "SELECT COUNT(0) FROM operation_link WHERE action=? AND functionItemId=? ";
		if (sqlHelper.queryCount(sql, action,functionItemId) == 0) {
			sql = "INSERT INTO operation_link(id,action,functionItemId,rowOperation,ordinal,subOrdinal) values(?,?,?,?,?,?)";
			sqlHelper.execute(sql, UniqueCode.make(), action, functionItemId,rowOperation, ordinal,subOrdinal);
		}
	}

	/**
	 * 初始化模块信息
	 */
	public void initFunctionModule() {
		clearOperationLink();

		List<String> list = actionScanner.getActionClassNameList();
		String parentId = null;
		String sql = null;
		for (String s : list) {
			Class<?> c = null;
			try {
				c = Class.forName(s);
			} catch (ClassNotFoundException e) {
				LogFactory.getLog(getClass()).error(e);
				continue;
			}

			if (ClassUtil.hasAnnotation(c, Module.class)) {
				Module module = c.getAnnotation(Module.class);
				String action = actionScanner.getAction(s,
						module.defaultFunctionName());
				if (StringUtil.isNullOrEmpty(action)) {
					continue;
				}
				parentId = findBelong(module);

				sql = "SELECT COUNT(0) FROM function_module WHERE id=?";
				if (sqlHelper.queryCount(sql, module.id()) == 0) {
					sql = "INSERT INTO function_module(id,name,action,ico,memo,parentId) values(?,?,?,?,?,?)";
					sqlHelper.execute(sql, module.id(), module.name(), action,
							module.ico(), module.memo(), parentId);
				}

				Method[] methods = c.getDeclaredMethods();
				for (Method method : methods) {
					
					// OperationLink <-------------------------------------
					if (method.isAnnotationPresent(OperationLink.class)) {
						OperationLink operationLink = method
								.getAnnotation(OperationLink.class);
						String npId=null;
						if (method.isAnnotationPresent(NeedPermission.class)) {
							npId=method
									.getAnnotation(NeedPermission.class).id();
						}else if (method
								.isAnnotationPresent(NeedPermissionTemplate.class)) {
							npId=method
									.getAnnotation(NeedPermissionTemplate.class).id();
						}
						if(npId!=null){
							try{
								checkSaveOperationLink(actionScanner.getAction(s, operationLink.link()), npId,operationLink.rowOperation(), operationLink.ordinal(),operationLink.subOrdinal());
							}catch(Throwable t){
								log.error(t);
							}
						}
					}else if (method.isAnnotationPresent(OperationLinks.class)) {
						OperationLinks operationLinks=method
								.getAnnotation(OperationLinks.class);
						for(OperationLink operationLink:operationLinks.value()){
							String npId=null;
							if (method.isAnnotationPresent(NeedPermission.class)) {
								npId=method
										.getAnnotation(NeedPermission.class).id();
							}else if (method
									.isAnnotationPresent(NeedPermissionTemplate.class)) {
								npId=method
										.getAnnotation(NeedPermissionTemplate.class).id();
							}
							if(npId!=null){
								try{
									checkSaveOperationLink(actionScanner.getAction(s, operationLink.link()), npId,operationLink.rowOperation(), operationLink.ordinal(),operationLink.subOrdinal());
								}catch(Throwable t){
									log.error(t);
								}
							}
						}
					}

					if (method.isAnnotationPresent(NeedPermission.class)) {
						NeedPermission needPermission = method
								.getAnnotation(NeedPermission.class);
						action = actionScanner.getAction(s, method.getName());
						parentId = findParent(needPermission.parent(), c);
						checkSaveFunctionItem(
								needPermission.id(), module.id(),
								needPermission.name(), action,
								needPermission.memo(), needPermission.ico(),
								parentId);
					} else if (method
							.isAnnotationPresent(NeedPermissionTemplate.class)) {
						NeedPermissionTemplate needPermissionTemplate = method
								.getAnnotation(NeedPermissionTemplate.class);
						action = actionScanner.getAction(s, method.getName());
						parentId = findParent(needPermissionTemplate.parent(),
								c);
						if (needPermissionTemplate.template().equals(
								NeedPermissionTemplate.CREATE)) {
							checkSaveFunctionItem(
									needPermissionTemplate.id(), module.id(),
									"添加", action, null, 
									"glyphicon glyphicon-plus", 
									//"image/system/add.gif",
									parentId);
						} else if (needPermissionTemplate.template().equals(
								NeedPermissionTemplate.UPDATE)) {
							checkSaveFunctionItem(
									needPermissionTemplate.id(), module.id(),
									"修改", action, null,
									"glyphicon glyphicon-pencil",
									//"image/system/modify.gif", 
									parentId);
						} else if (needPermissionTemplate.template().equals(
								NeedPermissionTemplate.DELETE)) {
							checkSaveFunctionItem(
									needPermissionTemplate.id(), module.id(),
									"删除", action, null,
									"glyphicon glyphicon-remove",
									//"image/system/delete.gif", 
									parentId);
						} else if (needPermissionTemplate.template().equals(
								NeedPermissionTemplate.DETAIL)) {
							checkSaveFunctionItem(
									needPermissionTemplate.id(), module.id(),
									"查看", action, null,
									"glyphicon glyphicon-zoom-in",
									//"image/system/view.gif", 
									parentId);
						} else if (needPermissionTemplate.template().equals(
								NeedPermissionTemplate.EXPORT)) {
							checkSaveFunctionItem(
									needPermissionTemplate.id(), module.id(),
									"导出", action, null,
									"glyphicon glyphicon-download-alt",
									//"image/system/export.gif", 
									parentId);
						} else if (needPermissionTemplate.template().equals(
								NeedPermissionTemplate.CONFIG)) {
							checkSaveFunctionItem(
									needPermissionTemplate.id(), module.id(),
									"设置", action, null,
									"glyphicon glyphicon-cog",
									//"image/system/config.gif", 
									parentId);
						}
					}
				}
			}
		}
	}

	/**
	 * 菜单初始化 OK
	 */
	public void initMenu() {
		String sql = "DELETE FROM menu_item_config";
		sqlHelper.execute(sql);
		sql = "DELETE FROM menu_config";
		sqlHelper.execute(sql);

		doConfigMenu("/menu.json",false);
	}
	
	private void doConfigMenu(String path,boolean mobile){
		InputStream inputStream = null;
		try {
			File file = new File(this.getClass().getClassLoader()
					.getResource(path).toURI());
			inputStream = new FileInputStream(file);
			int length = inputStream.available();
			byte[] bytes = new byte[length];
			inputStream.read(bytes, 0, length);
			String s = new String(bytes, "utf-8");

			MenuPacket[] menuPackets = jsonUtil.fromJson(s, MenuPacket[].class);
			for (int i = 0; i < menuPackets.length; i++) {
				if(StringUtil.isNullOrEmpty(menuPackets[i].getName())){
					continue;
				}
				
				List<MenuPacket> menuChildren = menuPackets[i].getChildren();
				if (menuChildren == null||menuChildren.size()==0) {
					continue;
				}
				doConfigMenu(menuPackets[i],null,i, mobile);
			}
		} catch (Exception e) {
			log.error(e);
			throw new SystemException();
		} finally {
			if (inputStream != null) {
				try {
					inputStream.close();
				} catch (IOException e) {
					log.error(e);
				}
				inputStream = null;
			}
		}
	}

	private void doConfigMenu(MenuPacket menuPacket,String parentId, int ordinal,boolean mobile) {
		if(!StringUtil.isNullOrEmpty(menuPacket.getId())){
			// 菜单项
			String sql = "INSERT INTO menu_item_config(id,menuConfigId,functionModuleId,ordinal) values(?,?,?,?)";
			if(mobile){
				sql = "INSERT INTO mobile_menu_item_config(id,menuConfigId,functionModuleId,ordinal) values(?,?,?,?)";
			}
			sqlHelper.execute(sql, UniqueCode.make(), parentId,menuPacket.getId(), ordinal);
		}else if(!StringUtil.isNullOrEmpty(menuPacket.getName())){
			String id = UniqueCode.make();
			String sql = "INSERT INTO menu_config(id,name,ico,parentId,ordinal) values(?,?,?,?,?)";
			if(mobile){
				sql = "INSERT INTO mobile_menu_config(id,name,ico,parentId,ordinal) values(?,?,?,?,?)";
			}
			sqlHelper.execute(sql, id, menuPacket.getName(),
					menuPacket.getIco(), parentId, ordinal);
			
			List<MenuPacket> menuChildren = menuPacket.getChildren();
			if (menuChildren != null&&menuChildren.size()>0) {
				for (int i = 0; i < menuChildren.size(); i++) {
					doConfigMenu(menuChildren.get(i),id,i, mobile);
				}
			}
		}
	}

	/**
	 * 初始化系统配置 OK
	 */
	@SuppressWarnings("static-access")
	public void initSystemConfig() {
		String sqlType="SELECT id FROM system_config_type";
		String sqlDetail="SELECT id FROM system_config_detail";
		
		String sqlInsertType="INSERT INTO system_config_type(id,name,allowConfig) VALUES(?,?,?)";
		String sqlInsertDetail="INSERT INTO system_config_detail(id,systemConfigTypeId,name,value,memo,allowConfig,ordinal) VALUES(?,?,?,?,?,?,?)";
		
		List<String> list = sqlHelper.queryForList(String.class, sqlDetail);
		List<String> listType = sqlHelper.queryForList(String.class, sqlType);
		
		Map<String, BaseConfig> map = SpringUtil.getApplicationContext()
				.getBeansOfType(BaseConfig.class);
		for (String key : map.keySet()) {
			BaseConfig baseConfig = map.get(key);
			Class<?> c = baseConfig.getClass();
			if(!c.isAnnotationPresent(SystemConfigType.class)){
				continue;
			}
			SystemConfigType systemConfigType=c.getAnnotation(SystemConfigType.class);
			String typeId=systemConfigType.id();
			if(!listType.contains(typeId)){
				String typeName=systemConfigType.caption();
				boolean allowConfig=systemConfigType.allowConfig();
				sqlHelper.execute(sqlInsertType, typeId,typeName,allowConfig);
			}
			
			List<IConfig> configs = baseConfig.getConfigList(c);
			for(IConfig config:configs){
				String id=config.getId();
				if(!list.contains(id)){
					String name=config.getCaption();
					String memo=config.getMemo();
					int ordinal=config.getOrdinal();
					String value=config.getValue().toString();
					boolean allow=config.isAllowConfig();
					
					list.add(id);
					sqlHelper.execute(sqlInsertDetail, id,typeId,name,value,memo,allow,ordinal);
				}
			}
		}
	}
}
